package cybertechcebu
{
	import cybertechcebu.enum.Commands;
	import cybertechcebu.enum.Responses;
	import cybertechcebu.task.ChangeDirTask;
	import cybertechcebu.task.FeaturesTask;
	import cybertechcebu.task.FileUploadTask;
	import cybertechcebu.task.ListDirTask;
	import cybertechcebu.task.ListDirWithCheckTask;
	import cybertechcebu.task.LoginTask;
	import cybertechcebu.task.SizeTask;
	import cybertechcebu.task.TaskEvent;
	import cybertechcebu.task.TaskQueue;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.FileReference;
	import flash.net.Socket;
	
	import flashx.textLayout.elements.ParagraphElement;
	import flashx.textLayout.elements.SpanElement;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.controls.DataGrid;
	import mx.controls.List;
	
	import spark.components.TextArea;

	public class FTPClient
	{
		private var username:String;
		private var password:String;
		private var host:String;
		private var port:int;

		private var commandSocket:Socket;

		private var _loggedIn:Boolean = false;
		private var _connected:Boolean = false;
		private var _currentDirectory:String = "/";
		private var _featureString:String;
		
		private var _remoteFileList:Array =[];
		private var _uploadables:ArrayCollection = new ArrayCollection();
		

		private var queue:TaskQueue = new TaskQueue();

		public function FTPClient()
		{
		}

		[Bindable]
		public function get loggedIn():Boolean
		{
			return _loggedIn;
		}

		public function set loggedIn(arg:Boolean):void
		{
			_loggedIn = arg;
		}
		
		[Bindable]
		public function get connected():Boolean
		{
			return _connected;
		}
		
		public function set connected(arg:Boolean):void
		{
			_connected = arg;
			loggedIn = arg;
		}	
		
		[Bindable]
		public function get remoteFileList():Array
		{
			return _remoteFileList;
		}

		public function set remoteFileList(list:Array):void
		{
			_remoteFileList = list;
		}

		[Bindable]
		public function get currentDirectory():String
		{
			return _currentDirectory;
		}

		public function set currentDirectory(arg:String):void
		{
			_currentDirectory = arg;
		}

		[Bindable]
		public function get uploadables():ArrayCollection
		{
			return _uploadables;
		}

		public function set uploadables(uploadables:ArrayCollection):void
		{
			_uploadables = uploadables;
		}
		
		public function get featureString():String{
			return _featureString;
		}
		
		public function set featureString(features:String):void
		{
			_featureString = features;
		}
		
		public function connect(host:String, port:int, username:String, password:String):void
		{
			this.username = username;
			this.password = password;
			this.host = host;
			this.port = port;

			commandSocket = new Socket();

			commandSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
	
			commandSocket.addEventListener(Event.CONNECT, onSocketConnect);
			
			commandSocket.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void
			{
				Console.error("Command socket error: " + e.toString());
				connected = false;
			});
			
			commandSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void
			{
				Console.error("Command socket error: " + e.toString());
				connected = false;
			});
			
			commandSocket.addEventListener(Event.CLOSE, function(e:Event):void
			{
				Console.progress("Command socket closed");
				connected = false;
			});
			
			commandSocket.connect(host, port);

		}
		
		private function onSocketConnect(e:Event):void{
			Console.progress("Command socket connected");
			connected = true;
			queue.addTask((new LoginTask(this, username, password)));
			queue.addTask(new FeaturesTask(this));
			queue.addTask(new ListDirTask(this));
		}

		private function onSocketData(e:ProgressEvent):void
		{

			var response:String = commandSocket.readUTFBytes(commandSocket.bytesAvailable);
			
			var responses:Array = response.match(/^.+/gm);
			
			for(var i:uint = 0, len:uint = responses.length; i < len; i++){
				handleResponse(new FTPResponse(responses[i]));	
			}
			
		}
		
		private function handleResponse(response:FTPResponse):void{
			Console.response(response.str);
			
			if (queue.currentTask)
			{
				queue.currentTask.handleResponse(response);
			}
		}
		
		public function addUploadable(file:FileReference):void
		{
			uploadables.addItem(new LocalFile(file));
		}
		
		public function startUpload():void
		{
			for (var i:int = 0, len:int = uploadables.length; i < len; i++)
			{
				queue.addTask(new FileUploadTask(this, uploadables[i]));
				queue.addTask(new SizeTask(this, uploadables[i]));
			}
			queue.addTask(new ListDirTask(this));
		}

		public function listRemoteFiles():void
		{
			queue.addTask(new ListDirTask(this));
		}

		public function changeDirectory(dir:String):void
		{
			queue.addTask(new ChangeDirTask(this, dir));
			queue.addTask(new ListDirTask(this, dir));
		}
		

		public function sendCommand(command:FTPCommand):void
		{
			Console.command(command.str);
			commandSocket.writeUTFBytes(command.command);
			commandSocket.flush();
		}
		
		public function sendPassword(command:FTPCommand):void{
		
			var pass:String = " ";
			for(var i:uint = 0, len:uint = command.arg.length; i < len; i++){
				pass += "*";
			}
			Console.command(Commands.PASS + pass);		
			commandSocket.writeUTFBytes(command.command);
			commandSocket.flush();	
		}

	}
}
